This is a race bug for
org.apache.commons.pool.impl.GenericObjectPool.
The expected exception is
java.lang.IllegalStateException
: Too many active instances: 3.
More details about this bug are at
POOL-120 JIRA page.
org.apache.commons.pool.impl.GenericObjectPool:
t1 t2 public void addObject() throws Exception {
assertOpen();
if (_factory == null) {
throw new IllegalStateException("Cannot add objects without a factory.");
}
1 Object obj = _factory.makeObject();
synchronized (this) {
try {
assertOpen();
4 addObjectToPool(obj, false);
} catch (IllegalStateException ex) { // Pool closed
try {
_factory.destroyObject(obj);
} catch (Exception ex2) {
// swallow
}
throw ex;
}
}
}
public Object borrowObject() throws Exception {
...
for(;;) {
ObjectTimestampPair pair = null;
synchronized (this) {
assertOpen();
// if there are any sleeping, just grab one of those
try {
3 pair = (ObjectTimestampPair)(_pool.removeFirst());
} catch(NoSuchElementException e) {
; /* ignored */
}
...
}
...
5 if(null == pair) {
try {
6 Object obj = _factory.makeObject();
...
}
...
}
...
}
public Object makeObject() {
synchronized (this) {
2 7 activeCount++;
if (activeCount > maxActive) {
8 throw new IllegalStateException(
"Too many active instances: " + activeCount);
}
}
...
Precondition: MaxActive is N, and N-1 active objects have been borrowed from pool. There are 0 idle objects in pool.
numIdle > 0 and the idle object evictor is set to run (timeBetweenEvictionRunsMillis > 0)
thread 1 is evictor thread and thread 2 is borrow thread.
a) because there are 0 idle objects in pool and minIdle is set to more than 0, thread 1 calls ensureMinIdle method to add
objects into pool after evicting. So t1 executes 1, and activeCount is added to N at 2 now.
b) before thread 1 adds the object generated at step a) into pool at 4, context switched, thread 2 executes 3. And
pair is set to null because pool is still empty.
c) context switched, thread 1 executes 4.
d) context switched, thread 2 checks if pair is null at 5. pair is null due to step b), so thread 2 goes to 6.
e) thread 2 executes 7, and activeCount is N+1.
f) thread 2 comes to 8, because activeCount (which is N+1) is larger than maxActicve (which is N) now.
This bug is reproduced under pool 1.4 and JDK 1.6.0_33.
Execute the following scripts to run the test to reproduce the bug (assume the location of the pool test project is pool_test_home).
Linux:
${pool_test_home}/scripts/120.sh
Windows:
%pool_test_home%\scripts\120.bat